#ifndef INFO_RETRIEVAL_H
#define INFO_RETRIEVAL_H
#include "type_traits.h"

/**
 * @brief Converts a value of any type to its string representation.
 * 
 * This function template attempts to convert a given argument of any type to its string representation.
 * It handles different categories of types including arithmetic types, enumerations, compound types,
 * and special cases like void and nullptr. The conversion strategy depends on the type category:
 * - For arithmetic types (int, float, etc.), it converts the value to a string.
 * - For enumeration types, it converts the underlying integer value to a string.
 * - For compound types, it further distinguishes between function pointers, lambdas, and classes.
 *   Function pointers are labeled as "Function Pointer", lambdas as "Lambda Function", and for classes,
 *   it returns the mangled name provided by typeid.
 * - Special cases for void and nullptr_t are handled explicitly.
 * 
 * @tparam T The type of the argument to be converted to a string.
 * @param arg The argument whose type is to be converted to a string.
 * 
 * @return std::string A string representation of the argument's type. The exact representation depends
 * on the argument's type category as described above.
 * 
 * @note This function uses C++'s constexpr if and type traits to handle different type categories at
 * compile time, ensuring efficiency. For classes, the mangled name is returned, which can be demangled
 * using compiler-specific demangling utilities if needed.
 * 
 * Example usage:
 * ```
 * int x = 10;
 * enum class Color { Red, Green, Blue };
 * Color c = Color::Red;
 * auto lambda = [](){ return 42; };
 * 
 * std::cout << type_to_string(x) << std::endl;       // Output: "10"
 * std::cout << type_to_string(c) << std::endl;       // Output might be the underlying value of `Color::Red`
 * std::cout << type_to_string(lambda) << std::endl;  // Output: "Lambda Function"
 * std::cout << type_to_string(type_to_string) << std::endl; // Output: "Function Pointer"
 * ```
 */
template<typename T>
std::string type_to_string(const T& arg) {
    if constexpr(std::is_arithmetic_v<T>) {
        return std::to_string(arg);
    } else if constexpr(std::is_enum_v<T>) {
        return std::to_string(static_cast<std::underlying_type_t<T>>(arg));
    } else if constexpr(std::is_compound_v<T>) {
        if constexpr(std::is_function_v<T>) {
            return "Function Pointer";
        } else if constexpr(is_lambda<T>::value) {
            return "Lambda Function";
        } else if constexpr(std::is_class_v<T>) {
            return typeid(arg).name();
        }
    } else {
        if constexpr(std::is_void_v<T>) {
            return "void";
        } else if constexpr(std::is_same_v<T, std::nullptr_t>) {
            return "nullptr";
        }
    }
}
/**
 * @brief Converts a variable number of arguments to a string representation.
 * 
 * This function takes any number of arguments and converts each to a string representation.
 * If there is only one argument, and it is a pointer, the function returns a string indicating
 * it is a pointer to the type of the pointed-to object. Otherwise, it returns the string representation
 * of the type directly. For multiple arguments, it concatenates their string representations, separated by
 * commas. This function is useful for debugging or logging purposes where a textual representation
 * of argument types is needed.
 * 
 * @tparam Args Variable template parameters, representing the types of the arguments.
 * @param args The arguments to be converted to their string representations.
 * 
 * @return std::string A string that represents the type or types of the input arguments. For a single
 * pointer argument, returns "Pointer to <type>)". For other single arguments, returns the type directly.
 * For multiple arguments, returns a comma-separated list of types.
 * 
 * @note This function relies on the `type_to_string` function, which must be defined elsewhere and should
 * be capable of converting a type to its string representation. The exact mechanism for type to string
 * conversion is dependent on the implementation of `type_to_string`.
 * 
 * Example usage:
 * ```
 * int a = 5;
 * double b = 3.14;
 * int* p = &a;
 * std::cout << args_to_string(a, b); // Output might be "int, double"
 * std::cout << args_to_string(p);    // Output might be "Pointer to int)"
 * ```
 */
template<typename... Args>
std::string args_to_string(Args&&... args) {
    if constexpr(sizeof...(args) == 1) {
        using T = std::tuple_element_t<0, std::tuple<Args...>>;  // 获取参数包中第一个元素的类型
        if constexpr(std::is_pointer_v<T>) {
            using U = std::remove_pointer_t<T>;  // 去除指针类型
            return "Pointer to " + type_to_string<U>() + ")";
        } else {
            // 如果参数不是指针
            return type_to_string(std::get<0>(std::forward_as_tuple(args...)));
        }
    } else {
        std::ostringstream oss;
        bool isFirst = true;
        // 使用折叠表达式处理参数包
        ((oss << (isFirst ? "" : ", ") << type_to_string(args), isFirst = false), ...);
        std::string result = oss.str(); // 从oss获取字符串
        return result;
    }
}

#endif // INFO_RETRIEVAL_H